import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:built_collection/built_collection.dart';
import 'package:mobile_app.core/core/application/models/app_navigator_transition_info.dart';
import 'package:mobile_app.core/core/domain/entities/learning_content/lexical_item/lexical_item.dart';
import 'package:mobile_app.core/core/domain/utils/either_extension.dart';
import 'package:mobile_app.core/learning_content/application/bloc/bloc.dart';
import 'package:mobile_app.core/root_navigator/application/bloc/bloc.dart';
import 'package:mobile_app.core/root_navigator/application/models/lexical_item_addition_page_model.dart';
import 'package:mobile_app.home.collections/lexical_item_addition_page/domain/use_cases/get_initial_data/use_case.dart';
import 'package:mobile_app.home.collections/lexical_item_addition_page/domain/use_cases/handle_learning_content_outer_update/use_case.dart';
import 'package:mobile_app.home.collections/lexical_item_addition_page/domain/use_cases/suggest_lexical_items/use_case.dart';

part 'bloc_state.dart';

class LexicalItemAdditionPageBloc extends Cubit<LexicalItemAdditionPageBlocState> {
  LexicalItemAdditionPageBloc({
    required LexicalItemAdditionPageModel pageModel,
    required LearningContentBloc learningContentBloc,
    required RootNavigatorBloc rootNavigatorBloc,
    required SuggestLexicalItems suggestLexicalItems,
    required GetInitialData getInitialData,
    required HandleLearningContentOuterUpdate handleLearningContentOuterUpdate,
  })  : _pageModel = pageModel,
        _learningContentBloc = learningContentBloc,
        _rootNavigatorBloc = rootNavigatorBloc,
        _suggestLexicalItems = suggestLexicalItems,
        _handleLearningContentOuterUpdate = handleLearningContentOuterUpdate,
        super(_getInitialState(
          learningContentBlocState: learningContentBloc.state!,
          getInitialData: getInitialData,
        )) {
    _learningContentBlocSubscription =
        learningContentBloc.stream.listen(_onLearningContentBlocStateChanged);
  }

  final LexicalItemAdditionPageModel _pageModel;
  final LearningContentBloc _learningContentBloc;
  final RootNavigatorBloc _rootNavigatorBloc;

  final SuggestLexicalItems _suggestLexicalItems;
  final HandleLearningContentOuterUpdate _handleLearningContentOuterUpdate;

  late final StreamSubscription<LearningContentBlocState> _learningContentBlocSubscription;

  static LexicalItemAdditionPageBlocState _getInitialState({
    required LearningContentBlocState learningContentBlocState,
    required GetInitialData getInitialData,
  }) {
    final result = getInitialData(
      lexicalItemMap: learningContentBlocState.lexicalItemMap,
    );

    return LexicalItemAdditionPageBlocState(
      suggestedLexicalItems: result.suggestedLexicalItems,
      lexicalItemProgressPercentMap: result.lexicalItemProgressPercentMap,
      trimmedPrefix: result.trimmedPrefix,
      isTitlePrefix: result.isTitlePrefix,
    );
  }

  void _onLearningContentBlocStateChanged(LearningContentBlocState learningContentBlocState) {
    final failureOrResult = _handleLearningContentOuterUpdate(
      customCollectionId: _pageModel.customCollectionId,
      collectionListItems: learningContentBlocState.collectionListItems,
      lexicalItemMap: learningContentBlocState.lexicalItemMap,
      trimmedPrefix: state.trimmedPrefix,
    );

    if (failureOrResult.isLeft()) {
      final failure = failureOrResult.asLeft();

      switch (failure) {
        case NonexistentCollectionLearningContentOuterUpdateHandlingFailure():
          _forceClosePage();
      }

      return;
    }

    final result = failureOrResult.asRight();

    emit(state.copyWith(
      suggestedLexicalItems: () => result.suggestedLexicalItems,
      lexicalItemProgressPercentMap: () => result.lexicalItemProgressPercentMap,
    ));
  }

  void requestLexicalItemSuggestion({
    required String prefix,
  }) {
    final lexicalItems = _learningContentBloc.state!.lexicalItemMap.values.toBuiltList();

    final result = _suggestLexicalItems(
      lexicalItems: lexicalItems,
      prefix: prefix,
    );

    emit(state.copyWith(
      suggestedLexicalItems: () => result.suggestedLexicalItems,
      trimmedPrefix: () => result.trimmedPrefix,
      isTitlePrefix: () => result.isTitlePrefix,
    ));
  }

  void _forceClosePage() {
    const transitionInfo = RemovalNavigatorTransitionInfo(
      hasAnimation: false,
    );

    _rootNavigatorBloc.closePage(
      pageModel: _pageModel,
      transitionInfo: transitionInfo,
    );
  }

  @override
  Future<void> close() {
    _learningContentBlocSubscription.cancel();
    return super.close();
  }
}
